package com.yonyou.pmclouds.plan.rmiimpl;

import com.alibaba.dubbo.config.annotation.Service;
import com.yonyou.pmclouds.ApplicationConsts;
import com.yonyou.pmclouds.basecom.bp.processor.AuditInfoUpdateProcessor;
import com.yonyou.pmclouds.basecom.bp.template.SingleDeleteBpTemplate;
import com.yonyou.pmclouds.basecom.bp.template.SingleInsertBpTemplate;
import com.yonyou.pmclouds.basecom.bp.template.SingleUpdateBpTemplate;
import com.yonyou.pmclouds.basecom.consts.BillTypeConst;
import com.yonyou.pmclouds.basecom.entity.SuperVO;
import com.yonyou.pmclouds.basecom.exception.BusinessException;
import com.yonyou.pmclouds.basecom.runtime.RuntimeEnvironment;
import com.yonyou.pmclouds.basecom.util.DateUtils;
import com.yonyou.pmclouds.organization.entity.OrganizationVO;
import com.yonyou.pmclouds.organization.rmiitf.OrganizationQuery;
import com.yonyou.pmclouds.plan.entity.ScheduleItemVO;
import com.yonyou.pmclouds.plan.entity.ScheduleReportVO;
import com.yonyou.pmclouds.plan.entity.ScheduleVO;
import com.yonyou.pmclouds.plan.mapper.ScheduleMapper;
import com.yonyou.pmclouds.plan.processor.*;
import com.yonyou.pmclouds.plan.rmiitf.IScheduleItemService;
import com.yonyou.pmclouds.plan.rmiitf.IScheduleQueryService;
import com.yonyou.pmclouds.plan.rmiitf.IScheduleService;
import com.yonyou.pmclouds.plantemplate.entity.ScheduleTemplateItemVO;
import com.yonyou.pmclouds.plantemplate.entity.ScheduleTemplateVO;
import com.yonyou.pmclouds.plantemplate.rmiitf.IScheduleTemplateQueryService;
import com.yonyou.pmclouds.project.entity.ProjectViewVO;
import com.yonyou.pmclouds.projecttype.entity.ProjectTypeVO;
import com.yonyou.pmclouds.projecttype.rmiitf.ProjectTypeQuery;
import com.yonyou.pmclouds.workflow.aspect.PMApprove;
import com.yonyou.pmclouds.workflow.service.rmiitf.IFlowApproveBuziService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * @Description: 进度计划编制服务类
 * @Author: zhangzhonghao
 * @Date: 2020-03-06
 */

@Service(version = ApplicationConsts.APPLICATION_VERSION, interfaceClass = IScheduleService.class)
public class ScheduleServiceImpl implements IScheduleService, IFlowApproveBuziService {

    @Autowired
    private ScheduleMapper scheduleMapper;

    @Autowired
    private ScheduleInsertBeforeProcessor insertBeforeProcessor;

    @Autowired
    private ScheduleInsertItemProcessor insertItemProcessor;

    @Autowired
    private ScheduleSetPlanDateProcessor setPlanDateProcessor;

    @Autowired
    private ScheduleUpdateBeforeProcessor updateBeforeProcessor;

    @Autowired
    private ScheduleUpdateItemProcessor updateItemProcessor;

    @Autowired
    private ScheduleDeleteAfterProcessor deleteAfterProcessor;

    @Autowired
    private ScheduleAdjustBeforeProcessor adjustBeforeProcessor;

    @Autowired
    private ScheduleAdjustItemProcessor adjustItemProcessor;

    @Autowired
    private IScheduleQueryService scheduleQueryService;

    @Autowired
    private IScheduleItemService itemService;

    @Autowired
    private OrganizationQuery organizationQuery;

    @Autowired
    private ProjectTypeQuery projectTypeQuery;

    @Autowired
    private IScheduleTemplateQueryService scheduleTemplateQueryService;

    /**
     * 计划编制新增
     *
     * @param scheduleVO 计划编制VO
     */
    @Override
    public ScheduleVO insert(ScheduleVO scheduleVO) throws BusinessException {
        if (StringUtils.isNotEmpty(scheduleVO.getPkSchedule())) {
            return update(scheduleVO);
        }

        SingleInsertBpTemplate<ScheduleVO> insertBpTemplate = new SingleInsertBpTemplate<>(scheduleMapper, false);

        // 校验必填项、设置默认值
        insertBpTemplate.addBeforeProcessor(insertBeforeProcessor);

        // 保存计划任务
        insertBpTemplate.addBeforeProcessor(insertItemProcessor);

        // 根据计划任务时间推算计划时间
        insertBpTemplate.addBeforeProcessor(setPlanDateProcessor);

        return insertBpTemplate.insert(scheduleVO);
    }

    /**
     * 计划编制删除
     *
     * @param scheduleVO 计划编制VO
     */
    @Override
    public ScheduleVO delete(ScheduleVO scheduleVO) throws BusinessException {
        SingleDeleteBpTemplate<ScheduleVO> deleteBpTemplate = new SingleDeleteBpTemplate<>(scheduleMapper);
        deleteBpTemplate.addAfterProcessor(deleteAfterProcessor);
        return deleteBpTemplate.delete(scheduleVO);
    }

    /**
     * 计划编制修改
     *
     * @param scheduleVO 计划编制VO
     */
    @Override
    public ScheduleVO update(ScheduleVO scheduleVO) throws BusinessException {
        SingleUpdateBpTemplate<ScheduleVO> updateBpTemplate = new SingleUpdateBpTemplate<>(scheduleMapper,
                new String[]{ScheduleVO.NAME, ScheduleVO.PLAN_START_DATE, ScheduleVO.PLAN_END_DATE, ScheduleVO.PLAN_DAYS,
                ScheduleVO.MODIFIER, ScheduleVO.MODIFY_TIME, ScheduleVO.CHANGE_FLAG});

        // 添加修改时间、修改人
        updateBpTemplate.addBeforeProcessor(new AuditInfoUpdateProcessor<ScheduleVO>());

        // 保存前校验
        updateBpTemplate.addBeforeProcessor(updateBeforeProcessor);

        // 修改任务项
        updateBpTemplate.addBeforeProcessor(updateItemProcessor);

        // 修改计划时间
        updateBpTemplate.addBeforeProcessor(setPlanDateProcessor);

        return updateBpTemplate.update(scheduleVO);
    }

    @Override
    public ScheduleReportVO updateProgress(ScheduleReportVO reportVO) throws BusinessException {
        if (reportVO == null) {
            return null;
        }

        itemService.updateProgress(reportVO);

        return reportVO;
    }

    /**
     * 计划审批提交
     *
     * @param scheduleVO 计划VO
     * @return 提交后计划VO
     */

    @Override
    @PMApprove(trigger = "commit")
    public ScheduleVO commit(ScheduleVO scheduleVO) throws BusinessException {
        return scheduleVO;
    }

    @Override
    public ScheduleVO updateScheduleForAdjust(ScheduleVO scheduleVO) throws BusinessException {
        String oldPkSchedule = scheduleVO.getPkSchedule();
        scheduleVO.setOldPkSchedule(oldPkSchedule);

        SingleInsertBpTemplate<ScheduleVO> insertBpTemplate = new SingleInsertBpTemplate<>(scheduleMapper);

        // 校验必填项、设置默认值
        insertBpTemplate.addBeforeProcessor(adjustBeforeProcessor);

        // 保存计划任务
        insertBpTemplate.addBeforeProcessor(adjustItemProcessor);

        // 根据计划任务时间推算计划时间
        insertBpTemplate.addBeforeProcessor(setPlanDateProcessor);

        ScheduleVO result = insertBpTemplate.insert(scheduleVO);

        // 修改旧版本
        ScheduleVO oldScheduleVO = scheduleQueryService.queryById(oldPkSchedule);
        if(oldScheduleVO == null){
            return result;
        }

        oldScheduleVO.setLastFlag("N");

        SingleUpdateBpTemplate<ScheduleVO> updateBpTemplate = new SingleUpdateBpTemplate<>(scheduleMapper,
                new String[]{ScheduleVO.LAST_FLAG, ScheduleVO.MODIFIER, ScheduleVO.MODIFY_TIME, ScheduleVO.CHANGE_FLAG});
        updateBpTemplate.addBeforeProcessor(new AuditInfoUpdateProcessor<ScheduleVO>());
        updateBpTemplate.update(oldScheduleVO);

        return result;
    }

    @Override
    @PMApprove
    public ScheduleVO addDefault(ScheduleVO scheduleVO) throws BusinessException {
        if(StringUtils.isEmpty(scheduleVO.getPkProject())){
            throw new BusinessException("项目主键不能为空");
        }
       //List<ScheduleVO> scheduleVOS = scheduleQueryService.queryByPkProject(scheduleVO.getPkProject());
        List<ScheduleVO> scheduleVOS = scheduleMapper.queryByPkProject(scheduleVO.getPkProject());
        if(scheduleVOS != null && scheduleVOS.size() > 0){
            for(ScheduleVO scheduleVOTemp : scheduleVOS){
                if(scheduleVOTemp.getName().equalsIgnoreCase(scheduleVO.getName()) && scheduleVOTemp.getCode().equalsIgnoreCase(scheduleVO.getCode())){
                    throw new BusinessException("已经添加默认计划，不允许重复添加！");
                }
            }
        }

        return this.insert(scheduleVO);
    }

    @Override
    public void savePlanAuto(ProjectViewVO projectViewVO) throws BusinessException {
        String pkTenant = RuntimeEnvironment.getTenantId();
        String pkOrg = projectViewVO.getPkOrg();
        String type = projectViewVO.getPkProjectType();
        String pkProject = projectViewVO.getPkProject();
        String projectName = projectViewVO.getSname();
        OrganizationVO organizationVO = organizationQuery.queryByPkSrc(pkTenant,pkOrg);
        if(null == organizationVO){
            return;
        }
        String pkOrganization = organizationVO.getPkOrganization();//组织id
        String organiationName = organizationVO.getSname();//组织名称

        ScheduleTemplateVO[] templetVOS = scheduleTemplateQueryService.autoSearchPlanTemp(pkTenant, pkOrganization, type);

        if(null == templetVOS || templetVOS.length == 0){
            return;
        }
        for(ScheduleTemplateVO template : templetVOS){
            //计划容器
            ScheduleVO scheduleVO = new ScheduleVO();
            scheduleVO.setPkProject(pkProject);
            //Sname->组织名称_项目名称_计划类型_模板名称
            ProjectTypeVO projectTypeVO = projectTypeQuery.queryById(type);
            StringBuilder builder = new StringBuilder();
            nameSplicing(projectName, organiationName, template, projectTypeVO, builder);
            scheduleVO.setName(builder.toString());
            scheduleVO.setCode(template.getCode());

            List<ScheduleItemVO> itemVOS = coverItemsByTemplate(template, scheduleVO);
            scheduleVO.setScheduleItemVOS(itemVOS.toArray(new ScheduleItemVO[]{}));
            insert(scheduleVO);
        }
    }


    private List<ScheduleItemVO> coverItemsByTemplate(ScheduleTemplateVO templateVO, ScheduleVO scheduleVO) throws BusinessException {
        ScheduleTemplateItemVO[] templateItemVOS = templateVO.getScheduleTemplateItemVOS();
        if(templateItemVOS == null || templateItemVOS.length <= 0){
            return new ArrayList<>();
        }

        List<ScheduleItemVO> scheduleItemVOS = new ArrayList<>();

        for(ScheduleTemplateItemVO templateItemVO : templateItemVOS){
            ScheduleItemVO rootItemVO = coverItemByTemplate(templateItemVO, scheduleVO);
            scheduleItemVOS.add(rootItemVO);
        }

        return scheduleItemVOS;
    }

    private ScheduleItemVO coverItemByTemplate(ScheduleTemplateItemVO templateItemVO, ScheduleVO scheduleVO) throws BusinessException {
        ScheduleItemVO itemVO = new ScheduleItemVO();
        itemVO.setPkProject(scheduleVO.getPkProject());
        itemVO.setCode(templateItemVO.getCode());
        itemVO.setName(templateItemVO.getName());
        itemVO.setDependPlanName(templateItemVO.getDependPlanName());
        itemVO.setRelatedBillType(templateItemVO.getRelatedBillType());
        itemVO.setManager(templateItemVO.getManager());
        itemVO.setManagerName(templateItemVO.getManagerName());
        itemVO.setPkMilestone(templateItemVO.getPkMilestone());
        itemVO.setMilestoneName(templateItemVO.getMilestoneName());
        itemVO.setMilestoneCode(templateItemVO.getMilestoneCode());
        itemVO.setRelatedBillTypeName(templateItemVO.getRelatedBillTypeName());
        itemVO.setPkDepartment(templateItemVO.getPkDepartment());
        itemVO.setDepartmentName(templateItemVO.getDepartmentName());

        Date startDate = Calendar.getInstance().getTime();
        int planDays = templateItemVO.getPlanDays();
        if (templateItemVO.getPlanDays() != null) {
            itemVO.setPlanDays(planDays);
            itemVO.setPlanStartDate(DateUtils.asDateBegin(DateUtils.formatDate(startDate)));
            Date endDate = DateUtils.calculateDate(startDate, (planDays - 1));
            itemVO.setPlanEndDate(DateUtils.asDateEnd(DateUtils.formatDate(endDate)));
        } else {
            itemVO.setPlanDays(1);
            itemVO.setPlanStartDate(DateUtils.asDateBegin(DateUtils.formatDate(startDate)));
            itemVO.setPlanEndDate(DateUtils.asDateEnd(DateUtils.formatDate(startDate)));
        }

        if(templateItemVO.getChildren() != null && templateItemVO.getChildren().length > 0){
            List<ScheduleItemVO> childItemVOS = new ArrayList<>();
            for(ScheduleTemplateItemVO childTemplateItemVO : templateItemVO.getChildren()){
                ScheduleItemVO childItemVO = coverItemByTemplate(childTemplateItemVO, scheduleVO);
                childItemVOS.add(childItemVO);
            }

            if(childItemVOS.size() > 0){
                itemVO.setChildren(childItemVOS.toArray(new ScheduleItemVO[]{}));
                itemVO.setChildCount(childItemVOS.size());
            }
        }

        return itemVO;

    }

    @Override
    public SuperVO approveByPkBill(String pk_bill, byte billStatus) throws BusinessException {
        return scheduleQueryService.queryById(pk_bill);
    }

    @Override
    public SuperVO rejectByPkBill(String pk_bill) throws BusinessException {
        return scheduleQueryService.queryById(pk_bill);
    }

    @Override
    public SuperVO queryDetailForWorkFlow(String pk_bill) throws BusinessException {
        return scheduleQueryService.queryById(pk_bill);
    }

    @Override
    public String getBillType() {
        return BillTypeConst.PROCESS_PLAN_BILLTYPE;
    }

    @Override
    public SuperVO deleteBill(SuperVO businessVO) throws BusinessException {
        return this.delete((ScheduleVO) businessVO);
    }

    @Override
    public Object getMapper() {
        return scheduleMapper;
    }

    /**
     * 自动生成计划命名规范拼接
     * @param projectName
     * @param organiationName
     * @param rootNode
     * @param projectTypeVO
     * @param builder
     */
    private void nameSplicing(String projectName, String organiationName, ScheduleTemplateVO rootNode, ProjectTypeVO projectTypeVO, StringBuilder builder) {
        if(StringUtils.isNotEmpty(organiationName)){
            builder.append(organiationName);
        }
        if(StringUtils.isNotEmpty(projectName)){
            builder.append("_").append(projectName);
        }
        if(StringUtils.isNotEmpty(projectTypeVO.getSname())){
            builder.append("_").append(projectTypeVO.getSname());
        }
        if(StringUtils.isNotEmpty(rootNode.getName())){
            builder.append("_").append(rootNode.getName());
        }
    }
}
